﻿@page "/"
@page "/{Page:int}"

@using Microsoft.EntityFrameworkCore

@inject IContactFilters Filters
@inject IDbContextFactory<ContactContext> DbFactory
@inject NavigationManager Nav
@inject GridQueryAdapter QueryAdapter

<h1>Contacts</h1>
<GridWrapper @ref="Wrapper"
             FilterChanged="ReloadAsync"
             DeleteRequested="id => Wrapper.DeleteRequestId = id">
    <div class="container-fluid contacts-grid">
        <div class="row">
            <div class="col-4"><NameToggle /></div>
            <div class="col-8"><TextFilter /></div>
        </div>
        <div class="row">&nbsp;</div>
        <div class="row">
            <div class="col-6">
                Page @Filters.PageHelper.Page of @Filters.PageHelper.PageCount:
                showing @Filters.PageHelper.PageItems of
                @Filters.PageHelper.TotalItemCount items.
                <a disabled="@(Filters.Loading || !Filters.PageHelper.HasPrev)"
                   class="btn btn-primary @IsDisabled(Filters.PageHelper.HasPrev)"
                   href="@Filters.PageHelper.PrevPage">
                    Previous
                </a>
                <a disabled="@(Filters.Loading || !Filters.PageHelper.HasNext)"
                   class="btn btn-primary @IsDisabled(Filters.PageHelper.HasNext)"
                   href="@Filters.PageHelper.NextPage">
                    Next
                </a>
            </div>
        </div>
        <div class="row">&nbsp;</div>
        <div class="row contact-header">
            <div class="col-1">&nbsp;</div>
            <div class="col-2"
                 @onclick="@(async ()=>await ToggleAsync(ContactFilterColumns.Name))">
                <SortIndicator Column="@(ContactFilterColumns.Name)" />&nbsp;Name
            </div>
            <div class="col-2"
                 @onclick="@(async ()=>await ToggleAsync(ContactFilterColumns.Phone))">
                <SortIndicator Column="@(ContactFilterColumns.Phone)" />&nbsp;📞 Phone
            </div>
            <div class="col-3"
                 @onclick="@(async ()=>await ToggleAsync(ContactFilterColumns.Street))">
                <SortIndicator Column="@(ContactFilterColumns.Street)" />&nbsp;🏠 Street Address
            </div>
            <div class="col-2"
                 @onclick="@(async ()=>await ToggleAsync(ContactFilterColumns.City))">
                <SortIndicator Column="@(ContactFilterColumns.City)" />&nbsp;City
            </div>
            <div class="col-1"
                 @onclick="@(async ()=>await ToggleAsync(ContactFilterColumns.State))">
                <SortIndicator Column="@(ContactFilterColumns.State)" />&nbsp;State
            </div>
            <div class="col-1"
                 @onclick="@(async ()=>await ToggleAsync(ContactFilterColumns.ZipCode))">
                <SortIndicator Column="@(ContactFilterColumns.ZipCode)" />&nbsp;ZipCode
            </div>
        </div>
        @if (Filters.Loading || Contacts == null)
        {
            <div class="row">
                <div class="col-12 alert alert-info">
                    Loading...
                </div>
            </div>
        }
        @if (Contacts != null && Contacts.Count == 0)
        {
            <div class="row">
                <div class="col-12 alert alert-warning">
                    No contacts found.
                </div>
            </div>
        }
        @if (Contacts != null)
        {
            @foreach (var contact in Contacts)
            {
                <ContactRow @key=contact CurrentContact="@contact"
                            DeleteContact="DeleteContactAsync" />
            }
        }
    </div>
</GridWrapper>

@code {
    /// <summary>
    /// The current page.
    /// </summary>
    [Parameter]
    public int Page
    {
        get => Filters.PageHelper.Page;
        set
        {
            Filters.PageHelper.Page = value;
        }
    }

    /// <summary>
    /// A wrapper for grid-related activity (like delete).
    /// </summary>
    private GridWrapper Wrapper { get; set; }

    /// <summary>
    /// Current page of <see cref="Contact"/>.
    /// </summary>
    private ICollection<Contact> Contacts { get; set; }

    /// <summary>
    /// Helper method to set disabled on class for paging.
    /// </summary>
    /// <param name="condition"><c>true</c> when the element is active (and therefore should not be disabled).</param>
    /// <returns>The string literal "disabled" or an empty string.</returns>
    private string IsDisabled(bool condition) =>
    !Filters.Loading && condition ? "" : "disabled";

    /// <summary>
    /// Keeps track of the last page loaded.
    /// </summary>
    private int _lastPage = -1;

    /// <summary>
    /// Main logic when getting started.
    /// </summary>
    /// <param name="firstRender"><c>true</c> for first-time render.</param>
    protected override void OnAfterRender(bool firstRender)
    {
        // Ensure we're on the same, er, right page.
        if (_lastPage < 1)
        {
            Nav.NavigateTo("/1");
            return;
        }

        // Normalize the page values.
        if (Filters.PageHelper.PageCount > 0)
        {
            if (Page < 1)
            {
                Nav.NavigateTo("/1");
                return;
            }
            if (Page > Filters.PageHelper.PageCount)
            {
                Nav.NavigateTo($"/{Filters.PageHelper.PageCount}");
                return;
            }
        }
        base.OnAfterRender(firstRender);
    }

    /// <summary>
    /// Triggered for any paging update.
    /// </summary>
    /// <returns>A <see cref="Task"/>.</returns>
    protected async override Task OnParametersSetAsync()
    {
        // Make sure the page really chagned.
        if (Page != _lastPage)
        {
            _lastPage = Page;
            await ReloadAsync();
        }
        await base.OnParametersSetAsync();
    }

    /// <summary>
    /// Used to toggle the grid sort. Will either switch to "ascending" on a new
    /// column, or toggle beteween "ascending" and "descending" on a column with the
    /// sort already set.
    /// </summary>
    /// <param name="col">The <see cref="ContactFilterColumns"/> to toggle.</param>
    /// <returns>A <see cref="Task"/>.</returns>
    private Task ToggleAsync(ContactFilterColumns col)
    {
        if (Filters.SortColumn == col)
        {
            Filters.SortAscending = !Filters.SortAscending;
        }
        else
        {
            Filters.SortColumn = col;
        }
        return ReloadAsync();
    }

    /// <summary>
    /// Deletes a contact.
    /// </summary>
    /// <returns>A <see cref="Task"/>.</returns>
    #region snippet1
    private async Task DeleteContactAsync()
    {
        using var context = DbFactory.CreateDbContext();

        Filters.Loading = true;

        var contact = await context.Contacts.FirstAsync(
            c => c.Id == Wrapper.DeleteRequestId);

        if (contact != null)
        {
            context.Contacts.Remove(contact);
            await context.SaveChangesAsync();
        }

        Filters.Loading = false;

        await ReloadAsync();
    }
    #endregion

    /// <summary>
    /// Reload page based on filters and paging controls.
    /// </summary>
    /// <returns>A <see cref="Task"/>.</returns>
    private async Task ReloadAsync()
    {
        if (Filters.Loading || Page < 1)
        {
            return;
        }

        Filters.Loading = true;

        if (Wrapper != null)
        {
            Wrapper.DeleteRequestId = 0;
        }

        Contacts = null;

        using var context = DbFactory.CreateDbContext();

        // run the query to load the current page
        Contacts = await QueryAdapter.FetchAsync(context.Contacts.AsQueryable());

        // now we're done
        Filters.Loading = false;
    }
}
